package com.jw.blog.config;




import com.jw.blog.shiro.realms.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author wan Email-wlf18726994755@163.com
 * @version 1.0
 * @date 2020/7/3 20:11
 **/
@Configuration
public class ShiroConfiguration {

    /**
     * 配置LifecycleBeanPostProcessor，可以自定义的来调用springIOC容器中Shiro Bean的生命周期方法
     * @return LifecycleBeanPostProcessor
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * *
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),
     * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * *
     * AuthorizationAttributeSourceAdvisor)即可实现此功能
     * * @return
     */

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 密码加密
     * @return 返回用来加密的bean
     */

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(1024);
        return credentialsMatcher;
    }

    /**
     * 配置realm,直接配置实现realm接口的bean
     * @return
     */
    @Bean
    public Realm realm() {

        ShiroRealm realm = new ShiroRealm();
        //进行加密操作
        realm.setCredentialsMatcher(this.hashedCredentialsMatcher());

        return realm;
    }


    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return ehCacheManager;
    }



    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //保存30天
        simpleCookie.setMaxAge(2592000);
        cookieRememberMeManager.setCookie(simpleCookie);
        cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j3Y+R1aSn5BOlAA=="));
        return cookieRememberMeManager;
    }


    @Bean
    public DefaultWebSecurityManager securityManager() {
        // 创建 DefaultWebSecurityManager 对象
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //启用缓存
        securityManager.setCacheManager(ehCacheManager());
        // 设置其使用的 Realm
        securityManager.setRealm(realm());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        // 创建 ShiroFilterFactoryBean 对象，用于创建 ShiroFilter 过滤器
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

        // 设置 SecurityManager
        filterFactoryBean.setSecurityManager(this.securityManager());

        // 设置 URL 们
        // 登陆 URL
       filterFactoryBean.setLoginUrl("/login");
        // 无权限 URL
        filterFactoryBean.setUnauthorizedUrl("/unauthorized");

        // 设置 URL 的权限配置
        filterFactoryBean.setFilterChainDefinitionMap(this.filterChainDefinitionMap());

        return filterFactoryBean;
    }

    private Map<String, String> filterChainDefinitionMap() {
        /**
         * anon 可以被匿名访问
         * authc 必须登陆后才可以访问的界面
         * logout 登出
         * roles 角色过滤器
         */
        // 注意要使用有序的 LinkedHashMap ，顺序匹配
        Map<String, String> filterMap = new LinkedHashMap<>();
        // 允许匿名访问
        filterMap.put("/login", "anon");
        filterMap.put("/unauthorized","anon");

//        // 需要 ADMIN 角色
        filterMap.put("/admin/updateBlog", "user");
        filterMap.put("/admin/addBlog", "user");
        filterMap.put("/admin/updateResource", "authc,roles[admin]");
        filterMap.put("/admin/deleteResource", "authc,roles[admin]");
        filterMap.put("/admin/addResource", "authc,roles[admin]");
        filterMap.put("/admin/deletePic", "authc,roles[admin]");
        filterMap.put("/admin/addBlogType", "authc,roles[admin]");
        filterMap.put("/admin/deleteBlogType", "authc,roles[admin]");
        filterMap.put("/admin/updateBlogType", "authc,roles[admin]");
        filterMap.put("/admin/addBlackIp", "authc,roles[admin]");
        filterMap.put("/admin/deleteBlackIp", "authc,roles[admin]");
        filterMap.put("/admin/deleteLinks", "authc,roles[admin]");
        filterMap.put("/admin/addLinks", "authc,roles[admin]");
        filterMap.put("/admin/updateLinks", "authc,roles[admin]");

        filterMap.put("/admin/**","user");
        // 退出
        filterMap.put("/logout", "logout");
        // 默认剩余的 URL ，需要经过认证
//        filterMap.put("/admin/**", "authc");
        filterMap.put("/**","anon");
        return filterMap;
    }


    /**
     * 使用注解没有权限不会返回500状态码
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();

        /*未授权处理页*/
        properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/unauthorized");
        /*身份没有验证*/
        properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/login");
        resolver.setExceptionMappings(properties);
        return resolver;
    }


}
